/*
 * @Author: wuqingchun
 * @Date: 2024-09-24 14:33:41
 * @Description: 
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-10-03 21:32:05
 */
#include "chat_errno.h"
#include "chat_session.h"


CChatSession::CChatSession(const char* pcServerHost, uint16_t usPort):
    m_objNet(pcServerHost, usPort)
    
{
    m_objNet.setMessageCallback(std::bind(&CChatSession::__OnMessage, this, _1, _2, _3));

    m_arrCmdHandler[CHAT_SESSION_CMD_CHAT] = std::bind(&CChatSession::__ChatWithFriend, this);
    m_arrCmdHandler[CHAT_SESSION_CMD_ADD_FRIEND] = std::bind(&CChatSession::__AddFriend, this);
    m_arrCmdHandler[CHAT_SESSION_CMD_CREATE_GROUP] = std::bind(&CChatSession::__CreateGroup, this);
    m_arrCmdHandler[CHAT_SESSION_CMD_JOIN_GROUP] = std::bind(&CChatSession::__JoinGroup, this);
    m_arrCmdHandler[CHAT_SESSION_CMD_EXIT_GROUP] = std::bind(&CChatSession::__ExitGroup, this);
    m_arrCmdHandler[CHAT_SESSION_CMD_LOGOUT] = std::bind(&CChatSession::__Logout, this);
    
}

int32_t CChatSession::RegisterUser(const char* pcName, const char* pcPassword)
{
    char acMsgBuf[256];
    CHAT_MSG_HEAD_S* pstHead = (CHAT_MSG_HEAD_S*)acMsgBuf;
    pstHead->uiMsgLen = sizeof(CHAT_MSG_USER_REGISTER_S);
    pstHead->usType = CHAT_MSG_REGISTER;
    pstHead->usVersion = 1;

    // pstHead->usType = htons(pstHead->usType );
    // pstHead->usVersion = htons(pstHead->usVersion );
    // pstHead->uiMsgLen = htonl(pstHead->uiMsgLen);

    CHAT_MSG_USER_REGISTER_S* pstBody = (CHAT_MSG_USER_REGISTER_S*)(acMsgBuf + sizeof(CHAT_MSG_HEAD_S));
    strcpy(pstBody->szUser, pcName);
    strcpy(pstBody->szPassword, pcPassword);

    printf("Send user register request\n");
    m_objNet.Send(*pstHead);
}

int32_t CChatSession::Login(const char* pcName, const char* pcPassword)
{
    char acMsgBuf[256];
    CHAT_MSG_HEAD_S* pstHead = (CHAT_MSG_HEAD_S*)acMsgBuf;
    pstHead->uiMsgLen = sizeof(CHAT_MSG_USER_LOGIN_S);
    pstHead->usType = CHAT_MSG_LOGIN;
    pstHead->usVersion = 1;

    // pstHead->usType = htons(pstHead->usType );
    // pstHead->usVersion = htons(pstHead->usVersion );
    // pstHead->uiMsgLen = htonl(pstHead->uiMsgLen);

    CHAT_MSG_USER_LOGIN_S* pstBody = (CHAT_MSG_USER_LOGIN_S*)(acMsgBuf + sizeof(CHAT_MSG_HEAD_S));
    strcpy(pstBody->szUser, pcName);
    strcpy(pstBody->szPassword, pcPassword);

    printf("Send user login request\n");
    m_objLoginUser.SetName(pcName);
    int32_t iErr = m_objNet.Send(*pstHead);
    if (iErr == CHAT_ERR_OK)
    {
        {
            std::unique_lock<std::mutex> objUL(m_objMtx);
            m_objCV.wait_for(objUL, std::chrono::milliseconds(10));
        }
        __MainMenu();
    }
}

int32_t CChatSession::Logout(const char* pcName)
{
    char acMsgBuf[256];
    CHAT_MSG_HEAD_S* pstHead = (CHAT_MSG_HEAD_S*)acMsgBuf;
    pstHead->uiMsgLen = sizeof(CHAT_MSG_USER_LOGOUT_S);
    pstHead->usType = CHAT_MSG_LOGOUT;
    pstHead->usVersion = 1;

    // pstHead->usType = htons(pstHead->usType );
    // pstHead->usVersion = htons(pstHead->usVersion );
    // pstHead->uiMsgLen = htonl(pstHead->uiMsgLen);

    CHAT_MSG_USER_LOGOUT_S* pstBody = (CHAT_MSG_USER_LOGOUT_S*)(acMsgBuf + sizeof(CHAT_MSG_HEAD_S));
    strcpy(pstBody->szUser, pcName);

    printf("Send user logout request\n");
    m_objNet.Send(*pstHead);
}

void CChatSession::__OnMessage(const TcpConnectionPtr& refConnPtr, Buffer* pobjBuf, Timestamp objTS)
{
    printf("Received a message\n");

    const char* pcMsg = pobjBuf->peek();
    size_t ulMsgLen = pobjBuf->readableBytes();
    if (ulMsgLen < sizeof(CHAT_MSG_HEAD_S))
    {
        printf("Received bad message!!!\n");

        return;
    }

    CHAT_MSG_HEAD_S* pstHead = (CHAT_MSG_HEAD_S*) pcMsg;

    pstHead->usType = htons(pstHead->usType);
    pstHead->uiMsgLen = htonl(pstHead->uiMsgLen);
    pstHead->usVersion = htons(pstHead->usVersion);

    if (pstHead->usType > CHAT_MSG_MAX)
    {
        printf("Unknown message type, %hu\n", pstHead->usType);
        return;
    }

    CHAT_MSG_SET_RESPONSE_S* pstRsp = (CHAT_MSG_SET_RESPONSE_S*)((char *)pstHead + sizeof(*pstHead));

    switch (pstHead->usType)
    {
        case CHAT_MSG_LOGIN_RSP:
        {
            m_objCV.notify_one();

            if (pstRsp->iErrNo == 0)
            {
                m_bLogin.store(true);
                printf("Login successfully, user=%s\n", m_objLoginUser.GetName().c_str());
            }
            else
            {
                printf("Login error, %d\n", pstRsp->iErrNo);
            }

            break;
        }
        case CHAT_MSG_LOGOUT_RSP:
        {
            if (pstRsp->iErrNo == 0)
            {
                m_bLogin.store(false);
            }
            printf("Logout response\n");
            break;
        }
        case CHAT_MSG_REGISTER_RSP:
        {
            printf("Register response\n");
            break;
        }
        default:
        {
            break;
        }
    }

    pobjBuf->retrieve(sizeof(CHAT_MSG_HEAD_S) + pstHead->uiMsgLen);
}

void CChatSession::__MainMenu()
{
    while (m_bLogin.load())
    {
        CHAT_SESSION_COMMAND_E enCmd = __GetCommand();
        if (enCmd == CHAT_SESSION_CMD_MAX)
        {
            continue;
        }

        m_arrCmdHandler[enCmd]();
    }
}

void CChatSession::__WaitInput(const char* pcPrompt, char* pcBuff, size_t ulBufLen)
{
    printf("%s: ", pcPrompt);
    char* pcLine = pcBuff;
    size_t ulLen = ulBufLen;
    ssize_t lResult = 0;
    do
    {
        lResult = getline(&pcLine, &ulLen, stdin);
    } while (lResult <= 1);

    // 删除换行符
    pcLine[lResult-1] = '\0';
}

CHAT_SESSION_COMMAND_E CChatSession::__GetCommand()
{
    char szLine[1024];
    CHAT_SESSION_COMMAND_E enCmd = CHAT_SESSION_CMD_MAX;
    static const char* apcMenu[CHAT_SESSION_CMD_MAX] = 
    {
        "Show this help",
        "One-on-one chat",
        "Add friend",
        "Create group",
        "Join group",
        "Exit group",
        "Logout"
    };

    for (int i = 0; i < CHAT_SESSION_CMD_MAX; i++)
    {
        printf("[%2d] - %s\n", i, apcMenu[i]);
    }

    __WaitInput("Enter your commond", szLine, sizeof(szLine));

    
    if (szLine[0] > '9' || szLine[0] < '0')
    {
        return CHAT_SESSION_CMD_MAX;
    }

    return (CHAT_SESSION_COMMAND_E)atoi(szLine);
}


void CChatSession::__ChatWithFriend()
{
    char acBuf[1024];

    CHAT_MSG_HEAD_S* pstHead = (CHAT_MSG_HEAD_S*)acBuf;
    CHAT_MSG_CHAT_S* pstChat = (CHAT_MSG_CHAT_S*)(acBuf + sizeof(CHAT_MSG_HEAD_S));
    __WaitInput("To", pstChat->szTo, sizeof(pstChat->szTo));
    __WaitInput("Message", pstChat->acData, 512);

    pstHead->usType = CHAT_MSG_CHAT;
    pstHead->uiMsgLen = sizeof(CHAT_MSG_CHAT_S) + 512;
    pstHead->usVersion = CHAT_VERSION;

    (void)m_objNet.Send(*pstHead);
}

void CChatSession::__AddFriend()
{

}

void CChatSession::__CreateGroup()
{

}

void CChatSession::__JoinGroup()
{

}

void CChatSession::__ExitGroup()
{

}

void CChatSession::__Logout()
{
    char szUser[CHAT_USER_MAXLEN];
    __WaitInput("User", szUser, sizeof(szUser));
    Logout(szUser);
}